home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
kernel
/
net
/
netArp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-18
|
27KB
|
893 lines
/*
* netArp.c --
*
* Routines for net arp and rarp.
*
* Copyright 1990 Regents of the University of California
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*/
#ifndef lint
static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/net/netArp.c,v 1.8 92/06/03 22:47:47 voelker Exp $ SPRITE (Berkeley)";
#endif /* not lint */
#include <sprite.h>
#include <sys.h>
#include <stdlib.h>
#include <timer.h>
#include <sync.h>
#include <rpc.h>
#include <netInt.h>
#include <netArp.h>
#include <string.h>
#include <stdio.h>
#include <rpcClient.h>
/*
* This flag turns on print statements in the ARP protocol
*/
Boolean arpDebug = FALSE;
ArpStatistics arpStatistics;
/*
* Current ARP transactions have their state linked together in
* a list so the packet handler can save the return address for
* the sender.
*/
static List_Links arpList;
static List_Links revArpList;
static Sync_Semaphore arpListMutex;
static ArpOutputQueue arpOutputQueue[ARP_OUTPUT_QUEUE_LEN];
static int nextOutputIndex = 0;
static Sync_Lock arpOutputQueueLock; ;
#define LOCKPTR (&arpOutputQueueLock)
static ArpInputQueue arpInputQueue[ARP_INPUT_QUEUE_LEN];
static int nextInputIndex = 0;
static Sync_Semaphore arpInputMutex;
static void Net_ArpTimeout _ARGS_((Timer_Ticks time, ClientData data));
static void NetArpHandler _ARGS_((ClientData data,
Proc_CallInfo *callInfoPtr));
static void NetArpOutput _ARGS_((Net_Interface *interPtr,
Net_EtherAddress *destEtherAddrPtr,
int etherType, NetSpriteArp *requestPtr));
static void NetFillInArpRequest _ARGS_((int command,
Net_NetworkType netType, int protocol,
ClientData targetId, ClientData senderId,
Net_Address *targetAddrPtr,
Net_Address *senderAddrPtr,
NetSpriteArp *requestPtr));
/*
*----------------------------------------------------------------------
*
* Net_ArpInit --
*
* Initializes the arp data structures.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
Net_ArpInit()
{
int i;
Sync_LockInitDynamic(&arpOutputQueueLock, "Net:arpOutputQueueLock");
Sync_SemInitDynamic(&arpInputMutex, "Net:arpInputMutex");
Sync_SemInitDynamic(&arpListMutex, "Net:arpListMutex");
/*
* Mark the arp output queue as all done (output).
*/
for (i=0; i<ARP_OUTPUT_QUEUE_LEN ; i++) {
arpOutputQueue[i].gather.done = TRUE;
}
List_Init(&arpList);
List_Init(&revArpList);
}
/*
*----------------------------------------------------------------------
*
* Net_Arp --
*
* Sprite's Address Resolution Protocol. Broadcast a Sprite ARP
* packet to find the physical address that is used to get to the
* host identified by the Sprite ID.
*
* Results:
* None.
*
* Side effects:
* A broadcast, and the route table is updated.
*
*----------------------------------------------------------------------
*/
ReturnStatus
Net_Arp(spriteID, mutexPtr)
int spriteID; /* ID to find the route for */
Sync_Semaphore *mutexPtr; /* Address of the mutex that the
* caller of Net_Output used for
* synchronization. This needs to
* be released during the ARP so that
* we can receive our reply. */
{
ReturnStatus status = FAILURE;
NetSpriteArp request; /* The Sprite ARP request packet data */
NetSpriteArp reply; /* The Sprite ARP reply packet data */
Net_ScatterGather gather; /* Points to packet data */
Net_Interface *interPtr;
Net_Route *routePtr;
int i;
for (i = 0; ; i++) {
routePtr = Net_IDToRoute(NET_BROADCAST_HOSTID, i, FALSE,
(Sync_Semaphore *) NIL, 0);
if (routePtr == (Net_Route *) NIL) {
break;
}
interPtr = routePtr->interPtr;
NetFillInArpRequest(NET_ARP_REQUEST, interPtr->netType,
NET_PROTO_RAW,
(ClientData) spriteID, (ClientData) rpc_SpriteID,
&interPtr->broadcastAddress,
&interPtr->netAddress[NET_PROTO_RAW],
&request);
gather.bufAddr = (Address)&request;
gather.length = sizeof(NetSpriteArp);
gather.done = FALSE;
gather.mutexPtr = (Sync_Semaphore *) NIL;
status = NetDoArp(routePtr, mutexPtr, NET_ARP_REQUEST, &gather,
&reply);
Net_ReleaseRoute(routePtr);
if (status == SUCCESS) {
Net_Address netAddress;
status = Net_SetAddress(NET_ADDRESS_ETHER,
(Address) ARP_SRC_ETHER_ADDR(&reply), &netAddress);
if (status != SUCCESS) {
panic("Net_Arp: Net_SetAddress failed\n");
}
(void) Net_InstallRoute(spriteID, interPtr, &netAddress,
NET_PROTO_RAW, "noname", "unknown", 0, RPC_MAX_SIZE,
(ClientData) 0);
return status;
}
}
return status;
}
/*
*----------------------------------------------------------------------
*
* Net_RevArp --
*
* Sprite's Reverse Address Resolution Protocol. Broadcast a Sprite
* Reverse ARP packet to find the Sprite ID or Internet address
* that corresponds to our network address.
*
* Results:
* A Sprite host ID
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
Net_RevArp(routePtr, protocol, netAddressPtr, mutexPtr)
Net_Route *routePtr; /* The route to use for the arp.*/
int protocol; /* Which protocol we are trying
* to resolve an address for. */
Net_Address *netAddressPtr; /* The address we are trying to
* resolve. */
Sync_Semaphore *mutexPtr; /* Mutex to release. */
{
ReturnStatus status;
NetSpriteArp request; /* Sprite RARP request packet data */
NetSpriteArp reply; /* Sprite RARP reply packet data */
Net_ScatterGather gather; /* Points to packet data */
Net_Interface *interPtr;
interPtr = routePtr->interPtr;
if (netAddressPtr == (Net_Address *) NIL) {
netAddressPtr = &interPtr->netAddress[NET_PROTO_RAW];
}
NetFillInArpRequest(NET_RARP_REQUEST, interPtr->netType,
protocol,
(ClientData) 0, (ClientData) 0,
netAddressPtr,
&interPtr->netAddress[NET_PROTO_RAW],
&request);
gather.bufAddr = (Address)&request;
gather.length = sizeof(NetSpriteArp);
gather.done = FALSE;
gather.mutexPtr = (Sync_Semaphore *) NIL;
status = NetDoArp(routePtr, mutexPtr, NET_RARP_REQUEST, &gather,
&reply);
if (status == SUCCESS) {
unsigned int value;
bcopy(ARP_TARGET_PROTO_ADDR(&reply),(char *) &value,4);
return(Net_NetToHostInt(value));
}
return -1;
}
/*
*----------------------------------------------------------------------
*
* NetDoArp --
*
* The broadcast-retry-wait loop for ARP and Reverse Arp.
*
* Results:
* Fills in the callers packet buffer with a copy of the reply.
* Returns FAILURE if there is no response after a timeout.
*
* Side effects:
* The packet broadcast, wait, etc.
*
*----------------------------------------------------------------------
*/
ReturnStatus
NetDoArp(routePtr, mutexPtr, command, gatherPtr, packetPtr)
Net_Route *routePtr; /* The route to use for the arp. */
Sync_Semaphore *mutexPtr; /* Address of the mutex that the
* caller of Net_Output used for
* synchronization. This needs to
* be released during the ARP so that
* we can receive our reply. */
int command; /* NET_ARP_REQUEST or NET_RARP_REQUEST*/
Net_ScatterGather *gatherPtr; /* Specifies the output packet */
NetSpriteArp *packetPtr; /* Filled in with the reply packet */
{
register Net_EtherHdr *etherHdrPtr; /* Regular RPC broadcast header */
Net_EtherHdr etherHdr; /* Header for Sprite ARP packet */
int retries = 0; /* Retry counter */
ArpState arp; /* State for the protocol */
NetSpriteArp *requestPtr; /* Pointer to request data */
List_Links *listPtr; /* Either arpList or revArpList */
Net_Interface *interPtr; /* Network interface. */
/*
* If we are aren't passed a mutexPtr then assume we can't do an
* Arp. This is because we are either at interrupt level or there
* are high-level locks that cannot be released.
*/
if (mutexPtr == (Sync_Semaphore *) NIL) {
return FAILURE;
}
if (Mach_AtInterruptLevel()) {
panic("NetDoArp: at interrupt level!!!");
}
interPtr = routePtr->interPtr;
switch(interPtr->netType) {
case NET_NETWORK_ETHER : {
/*
* Set up the ethernet header for the Arp request packet. We can't
* use the regular broadcast route because the ethernet protocol
* type is different, Arp. The broadcast destination address,
* however, is obtained from the regular broadcast route.
*/
etherHdrPtr = (Net_EtherHdr *)routePtr->headerPtr[NET_PROTO_RAW];
NET_ETHER_ADDR_COPY(NET_ETHER_HDR_DESTINATION(*etherHdrPtr),
NET_ETHER_HDR_DESTINATION(etherHdr));
if (command == NET_ARP_REQUEST) {
NET_ETHER_HDR_TYPE(etherHdr) =
Net_HostToNetShort(NET_ETHER_ARP);
} else {
NET_ETHER_HDR_TYPE(etherHdr) =
Net_HostToNetShort(NET_ETHER_REVARP);
}
break;
}
default:
printf("NetDoArp :Invalid route (bad network type %d)\n",
routePtr->interPtr->netType);
return FAILURE;
}
requestPtr = (NetSpriteArp *)gatherPtr->bufAddr;
/*
* Use a simple retry loop to get our reply. The ARP protocol state
* is set up and put on a list so the packet handler can find it.
*/
arp.state = ARP_WANT_REPLY;
arp.mutexPtr = mutexPtr;
arp.type = Net_NetToHostShort((requestPtr->arpHeader.protocolType));
if (command == NET_ARP_REQUEST) {
int spriteID;
bcopy(ARP_TARGET_PROTO_ADDR(requestPtr),(char *) &spriteID,4);
arp.id = (ClientData) Net_NetToHostInt((unsigned int)spriteID);
listPtr = &arpList;
} else {
arp.id = (ClientData) ARP_TARGET_ETHER_ADDR(requestPtr);
listPtr = &revArpList;
}
MASTER_LOCK(&arpListMutex);
List_InitElement((List_Links *) &arp);
List_Insert((List_Links *)&arp, LIST_ATREAR(listPtr));
MASTER_UNLOCK(&arpListMutex);
while (retries < 4 && ((arp.state & ARP_HAVE_INPUT) == 0)) {
retries++;
if (command == NET_ARP_REQUEST) {
if (arpDebug) {
printf("Sending arp request for %d\n", arp.id);
}
arpStatistics.numArpRequests++;
} else {
if (arpDebug) {
printf("Sending rev arp request\n");
}
arpStatistics.numRevArpRequests++;
}
(void) (interPtr->output)(interPtr, (Address) ðerHdr, gatherPtr, 1,
FALSE, (ReturnStatus *) NIL);
arp.state |= ARP_IN_TIMEOUT_QUEUE ;
arp.timeout.routine = Net_ArpTimeout;
arp.timeout.interval = 500 * timer_IntOneMillisecond;
arp.timeout.clientData = (ClientData)&arp;
Timer_ScheduleRoutine(&arp.timeout, TRUE);
do {
Sync_MasterWait(&arp.condition, arp.mutexPtr, FALSE);
} while (((arp.state & ARP_HAVE_INPUT) == 0) &&
(arp.state & ARP_IN_TIMEOUT_QUEUE));
}
MASTER_LOCK(&arpListMutex);
List_Remove((List_Links *)&arp);
MASTER_UNLOCK(&arpListMutex);
if (arp.state & ARP_IN_TIMEOUT_QUEUE) {
Timer_DescheduleRoutine(&arp.timeout);
}
if ((arp.state & ARP_HAVE_INPUT) == 0) {
arpStatistics.numTimeouts++;
return(FAILURE);
} else {
*packetPtr = arp.packet;
return(SUCCESS);
}
}
/*
*----------------------------------------------------------------------
*
* NetArpInput --
*
* Handler for the Address Resolution Protocol. This looks through
* the list of arpState's to find a match between the Sprite IDs.
* Upon a match the physical address from the reply is stored in
* the state and the waiting process is notified.
*
* Results:
* None.
*
* Side effects:
* Copies the data from the arp reply into the arp state that
* was enqueued in arpList by Net_Arp. The arpState is marked
* as having received input.
*
*----------------------------------------------------------------------
*/
/*ARGSUSED*/
void
NetArpInput(interPtr, packetPtr, packetLength)
Net_Interface *interPtr; /* The interface that got the
* packet. */
Address packetPtr; /* Pointer to the packet in the hardware
* recieve buffers */
int packetLength; /* Length of the packet */
{
register NetSpriteArp *arpDataPtr;
Boolean forKernel = TRUE;
short opcode, type;
ReturnStatus status;
switch(interPtr->netType) {
case NET_NETWORK_ETHER: {
arpDataPtr = (NetSpriteArp *)(packetPtr + sizeof(Net_EtherHdr));
break;
}
default :
return;
}
opcode = Net_NetToHostShort(arpDataPtr->arpHeader.opcode);
type = Net_NetToHostShort(arpDataPtr->arpHeader.protocolType);
/*
* This packet is for the kernel ARP if the following
* condition are true:
* 1) The hardwareType of the request is for the ethernet.
* 2) The protocolType is ether for IP or Sprite type.
* 3) The opcode is one we can handle (1 thru 4).
*/
forKernel = (Net_NetToHostShort(arpDataPtr->arpHeader.hardwareType) ==
NET_ARP_TYPE_ETHER) &&
((type == NET_ETHER_IP) || (type == NET_ETHER_SPRITE)) &&
((opcode > 0) && (opcode < 5)) ;
if (!forKernel) {
return;
}
switch (opcode) {
case NET_ARP_REQUEST: {
unsigned int id;
/*
* Received a request for the address corresponding to a
* sprite ID. Look to see if it is for us.
* If it is then we reply with that info.
*/
bcopy(ARP_TARGET_PROTO_ADDR(arpDataPtr),(char *)&id,4);
id = Net_NetToHostInt(id);
if (arpDebug) {
printf("Got ARP request for Sprite ID 0x%x\n", id);
}
if (type == NET_ETHER_SPRITE) {
forKernel = (id == rpc_SpriteID);
} else {
forKernel =
(id == interPtr->netAddress[NET_PROTO_INET].address.inet);
}
if (forKernel) {
/*
* We might overrun ourselves if we get a whole
* bunch of arp requests. We synchronize, however,
* so that the call-back procedure sees a
* consistent view.
*/
register ArpInputQueue *arpInputPtr;
MASTER_LOCK(&arpInputMutex);
arpInputPtr = &arpInputQueue[nextInputIndex];
arpInputPtr->interPtr = interPtr;
arpInputPtr->packet = *arpDataPtr;
nextInputIndex = (nextInputIndex + 1) % ARP_INPUT_QUEUE_LEN;
MASTER_UNLOCK(&arpInputMutex);
Proc_CallFunc(NetArpHandler, (ClientData)arpInputPtr, 0);
}
break;
}
case NET_ARP_REPLY: {
ArpState *arpPtr;
unsigned int id;
/*
* Make sure this REPLY is targeted for us.
*/
if (Net_EtherAddrCmp(
interPtr->netAddress[NET_PROTO_RAW].address.ether,
(* ARP_TARGET_ETHER_ADDR(arpDataPtr)))) {
if (arpDebug) {
char buf[20];
(void) Net_EtherAddrToString(
ARP_TARGET_ETHER_ADDR(arpDataPtr), buf);
printf("Ignoring reply for %s\n", buf);
}
break;
}
/*
* Look through the list of active arp requests for the one
* that matches this reply. Then just copy the arp data to
* that state and notify the waiting process.
* Note: we'll probably get many replies to each arp request
* and only the first one updates the waiting process's arp
* state. This is probably overly paranoid, but we don't want
* to be messing with things once we've notified the waiter.
*/
bcopy(ARP_SRC_PROTO_ADDR(arpDataPtr),(char *)&id,4);
id = Net_NetToHostInt(id);
if (arpDebug) {
printf("Got ARP reply for type %d Id 0x%x\n", type, id);
}
MASTER_LOCK(&arpListMutex);
LIST_FORALL(&arpList, (List_Links *)arpPtr) {
if ((arpPtr->id == (ClientData) id) && (arpPtr->type == type)) {
if ((arpPtr->state & ARP_HAVE_INPUT) == 0) {
arpPtr->packet = *arpDataPtr;
arpPtr->state |= ARP_HAVE_INPUT;
Sync_MasterBroadcast(&arpPtr->condition);
if (arpDebug) {
printf("Woke ARP list type %d id %d\n",arpPtr->type,
arpPtr->id);
}
}
}
}
MASTER_UNLOCK(&arpListMutex);
break;
}
case NET_RARP_REQUEST: {
/*
* Look in our route table for an entry with the ethernet
* address of the sender. If one is found, return a reply
* containing the corresponding Sprite ID. The kernel only
* handles NET_ETHER_SPRITE requests.
*/
int spriteID;
Net_Address netAddress;
if (type == NET_ETHER_SPRITE) {
status = Net_SetAddress(NET_ADDRESS_ETHER,
(Address) ARP_TARGET_ETHER_ADDR(arpDataPtr), &netAddress);
if (status != SUCCESS) {
panic("NetArpInput: Net_SetAddress failed\n");
}
spriteID = Net_AddrToID(&netAddress);
if (arpDebug) {
printf("Got REV_ARP request for Sprite ID 0x%x\n",
spriteID);
}
if (spriteID > 0) {
register ArpInputQueue *arpInputPtr;
MASTER_LOCK(&arpInputMutex);
arpInputPtr = &arpInputQueue[nextInputIndex];
arpInputPtr->interPtr = interPtr;
arpInputPtr->packet = *arpDataPtr;
nextInputIndex = (nextInputIndex + 1) %
ARP_INPUT_QUEUE_LEN;
MASTER_UNLOCK(&arpInputMutex);
Proc_CallFunc(NetArpHandler, (ClientData)arpInputPtr,0);
}
}
break;
}
case NET_RARP_REPLY: {
ArpState *arpPtr;
if (Net_EtherAddrCmp(
interPtr->netAddress[NET_PROTO_RAW].address.ether,
(* ARP_TARGET_ETHER_ADDR(arpDataPtr)))) {
break;
}
/*
* Make sure there is still a waiting process for this reply,
* then copy the reply into the waiting arp state.
*/
if (arpDebug) {
printf("Got REV_ARP reply for type %d\n",type);
}
MASTER_LOCK(&arpListMutex);
LIST_FORALL(&revArpList, (List_Links *)arpPtr) {
if ((arpPtr->type == type) &&
(!Net_EtherAddrCmpPtr(ARP_TARGET_ETHER_ADDR(arpDataPtr),
(Net_EtherAddress *) (arpPtr->id)))) {
if ((arpPtr->state & ARP_HAVE_INPUT) == 0) {
arpPtr->packet = *arpDataPtr;
arpPtr->state |= ARP_HAVE_INPUT;
Sync_MasterBroadcast(&arpPtr->condition);
if (arpDebug) {
printf("Woke REV_ARP reply for type %d\n",type);
}
}
}
}
MASTER_UNLOCK(&arpListMutex);
break;
}
}
return;
}
/*
*----------------------------------------------------------------------
*
* NetArpHandler --
*
* Routine to send an arp reply. Called via Proc_CallFunc.
* This returns an ethernet address given a Sprite ID. The
* interrupt handler has already checked in the netRouteArray for
* a good route for the spriteID.
*
* Results:
* None.
*
* Side effects:
* Generates a arp reply packet.
*
*----------------------------------------------------------------------
*/
/*ARGSUSED*/
static void
NetArpHandler(data, callInfoPtr)
ClientData data; /* Pointer into arpInputQueue */
Proc_CallInfo *callInfoPtr;
{
Net_Interface *interPtr;
ArpInputQueue *arpInputPtr = (ArpInputQueue *)data;
NetSpriteArp *arpDataPtr, request;
unsigned short opcode, type;
ReturnStatus status;
MASTER_LOCK(&arpInputMutex);
interPtr = arpInputPtr->interPtr;
arpDataPtr = &arpInputPtr->packet;
opcode = Net_NetToHostShort(arpDataPtr->arpHeader.opcode);
type = Net_NetToHostShort(arpDataPtr->arpHeader.protocolType);
if ((type != NET_ETHER_SPRITE) && (type != NET_ETHER_IP)) {
MASTER_UNLOCK(&arpInputMutex);
panic("Bad type %d in NetArpHandler\n", type);
return;
}
if (opcode == NET_ARP_REQUEST) {
Net_Address netAddress;
status = Net_SetAddress(NET_ADDRESS_ETHER,
(Address) ARP_SRC_ETHER_ADDR(arpDataPtr), &netAddress);
if (status != SUCCESS) {
panic("NetArpHandler: Net_SetAddress failed\n");
}
if (type == NET_ETHER_SPRITE) {
int spriteID;
bcopy(ARP_SRC_PROTO_ADDR(arpDataPtr),(char*)&spriteID,sizeof(int));
NetFillInArpRequest(NET_ARP_REPLY, interPtr->netType,
NET_PROTO_RAW,
(ClientData) spriteID, (ClientData) rpc_SpriteID,
&netAddress, &interPtr->netAddress[NET_PROTO_RAW],
&request);
} else {
Net_Address inetAddress;
Net_InetAddress tmp;
bcopy(ARP_SRC_PROTO_ADDR(arpDataPtr), (char *)&tmp,
sizeof(Net_InetAddress));
status = Net_SetAddress(NET_ADDRESS_INET, (Address) &tmp,
&inetAddress);
if (status != SUCCESS) {
panic("NetArpHandler: Net_SetAddress failed\n");
}
NetFillInArpRequest(NET_ARP_REPLY, interPtr->netType,
NET_PROTO_INET,
(ClientData) inetAddress.address.inet,
(ClientData) interPtr->netAddress[NET_PROTO_INET].address.inet,
&netAddress, &interPtr->netAddress[NET_PROTO_RAW],
&request);
}
NetArpOutput(interPtr, &netAddress.address.ether, NET_ETHER_ARP,
&request);
} else if (opcode == NET_RARP_REQUEST) {
Net_Address netAddress;
int spriteID;
status = Net_SetAddress(NET_ADDRESS_ETHER,
(Address) ARP_TARGET_ETHER_ADDR(arpDataPtr), &netAddress);
if (status != SUCCESS) {
panic("NetArpHandler: Net_SetAddress failed\n");
}
spriteID = Net_AddrToID(&netAddress);
if (spriteID > 0) {
NetFillInArpRequest(NET_RARP_REPLY, interPtr->netType,
NET_PROTO_RAW,
(ClientData) spriteID, (ClientData) rpc_SpriteID,
&netAddress, &interPtr->netAddress[NET_PROTO_RAW],
&request);
NetArpOutput(interPtr, ARP_SRC_ETHER_ADDR(arpDataPtr),
NET_ETHER_REVARP, &request);
}
} else {
MASTER_UNLOCK(&arpInputMutex);
panic ("Bad opcode %d in NetArpHandler\n", opcode);
return;
}
MASTER_UNLOCK(&arpInputMutex);
callInfoPtr->interval = 0;
return;
}
/*
*----------------------------------------------------------------------
*
* NetArpOutput --
*
* Routine to send an arp packet.
*
* Results:
* None.
*
* Side effects:
* Generates a Sprite arp packet.
*
*----------------------------------------------------------------------
*/
/*ARGSUSED*/
static void
NetArpOutput(interPtr, destEtherAddrPtr, etherType, requestPtr)
Net_Interface *interPtr;
Net_EtherAddress *destEtherAddrPtr; /* Host to send to */
int etherType; /* Type of ethernet packet to send. */
NetSpriteArp *requestPtr; /* Request to send. */
{
register Net_EtherHdr *etherHdrPtr;
register Net_ScatterGather *gatherPtr;
register NetSpriteArp *packetPtr;
if (interPtr->netType != NET_NETWORK_ETHER) {
printf("NetArpOutput: invalid network type %d\n", interPtr->netType);
return;
}
LOCK_MONITOR;
etherHdrPtr = &arpOutputQueue[nextOutputIndex].etherHdr;
packetPtr = &arpOutputQueue[nextOutputIndex].packet;
gatherPtr = &arpOutputQueue[nextOutputIndex].gather;
if (! gatherPtr->done) {
printf("Warning: NetArpOutput can't queue packet");
UNLOCK_MONITOR;
return;
}
nextOutputIndex = (nextOutputIndex + 1) % ARP_OUTPUT_QUEUE_LEN;
NET_ETHER_ADDR_COPY(*destEtherAddrPtr,
NET_ETHER_HDR_DESTINATION(*etherHdrPtr));
NET_ETHER_HDR_TYPE(*etherHdrPtr) =
Net_HostToNetShort((unsigned short)etherType);
#ifdef sun4
/*
* Gcc for the sun4 currently allows these structures to be on unaligned
* boundaries and then generates loads and stores as if they were aligned,
* so I have to copy them byte by byte.
*/
bcopy((char *)requestPtr, (char *)packetPtr, sizeof (NetSpriteArp));
#else
*packetPtr = *requestPtr;
#endif sun4
gatherPtr->bufAddr = (Address)packetPtr;
gatherPtr->length = sizeof(NetSpriteArp);
gatherPtr->done = FALSE;
gatherPtr->mutexPtr = (Sync_Semaphore *) NIL;
arpStatistics.numRevArpReplies++;
(void) (interPtr->output)(interPtr, (Address) etherHdrPtr, gatherPtr, 1,
FALSE, (ReturnStatus *) NIL);
UNLOCK_MONITOR;
return;
}
/*
*----------------------------------------------------------------------
*
* Net_ArpTimeout --
*
* Timeout routine for ARP. This just notifies the waiting process.
*
* Results:
* None.
*
* Side effects:
* Wakes up the process waiting for an ARP reply.
*
*----------------------------------------------------------------------
*/
/*ARGSUSED*/
static void
Net_ArpTimeout(time, data)
Timer_Ticks time; /* The time we timed out at. */
ClientData data; /* Out private data is a pointer to the
* arp protocol state. */
{
ArpState *arpPtr = (ArpState *)data;
MASTER_LOCK(arpPtr->mutexPtr);
if (arpDebug) {
printf("Arp timeout\n");
}
arpPtr->state &= ~ARP_IN_TIMEOUT_QUEUE;
Sync_MasterBroadcast(&arpPtr->condition);
MASTER_UNLOCK(arpPtr->mutexPtr);
return;
}
/*
*----------------------------------------------------------------------
*
* NetFillInArpRequest --
*
* Build a ARP or RARP packet in the provided request buffer.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void
NetFillInArpRequest(command, netType, protocol, targetId, senderId,
targetAddrPtr, senderAddrPtr, requestPtr)
short command; /* ARP opcode to perform. */
Net_NetworkType netType;
int protocol;
ClientData targetId; /* Target protocol address. */
ClientData senderId; /* Sender's protocol ID. */
Net_Address *targetAddrPtr; /* Target network address. */
Net_Address *senderAddrPtr; /* Sender'network address. */
NetSpriteArp *requestPtr; /* Arp request packet to fill in. */
{
unsigned int tid;
unsigned int sid;
ReturnStatus status;
switch (netType) {
case NET_NETWORK_ETHER: {
requestPtr->arpHeader.hardwareType =
Net_HostToNetShort(NET_ARP_TYPE_ETHER);
requestPtr->arpHeader.hardwareAddrLen = sizeof(Net_EtherAddress);
requestPtr->arpHeader.opcode =
Net_HostToNetShort((unsigned short)command);
switch (protocol) {
case NET_PROTO_RAW: {
requestPtr->arpHeader.protocolType =
Net_HostToNetShort(NET_ETHER_SPRITE);
requestPtr->arpHeader.protocolAddrLen = sizeof(int);
break;
}
case NET_PROTO_INET: {
requestPtr->arpHeader.protocolType =
Net_HostToNetShort(NET_ETHER_IP);
requestPtr->arpHeader.protocolAddrLen =
sizeof(Net_InetAddress);
break;
}
default:
panic("NetFillInArpRequest: Unknown protocol %d\n",
protocol);
}
status = Net_GetAddress(targetAddrPtr,
(Address) ARP_TARGET_ETHER_ADDR(requestPtr));
if (status != SUCCESS) {
printf(
"NetFillInArpRequest: Net_GetAddress of target address failed\n");
return;
}
status = Net_GetAddress(senderAddrPtr,
(Address) ARP_SRC_ETHER_ADDR(requestPtr));
if (status != SUCCESS) {
printf(
"NetFillInArpRequest: Net_GetAddress of sender address failed\n");
return;
}
break;
}
default: {
panic("Warning: NetFillInArpRequest: bad netType %d\n", netType);
}
}
tid = Net_HostToNetInt((unsigned int) targetId);
sid = Net_HostToNetInt((unsigned int) senderId);
bcopy((char *) &sid, ARP_SRC_PROTO_ADDR(requestPtr),sizeof(int));
bcopy((char *) &tid, ARP_TARGET_PROTO_ADDR(requestPtr),sizeof(int));
return;
}